{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# 手机价格分类"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "3c8aaf6feaeddff1"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 1. 导包"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "f353f9546fac9ef0"
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:12:43.518980Z",
     "start_time": "2025-10-11T04:12:40.636203800Z"
    }
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.model_selection import train_test_split\n",
    "import torch\n",
    "from torch.utils.data import TensorDataset, DataLoader\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "import time\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from torchinfo import summary"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 2.构建数据集 "
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "daadc8d4a2fe829f"
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "data": {
      "text/plain": "   battery_power  blue  clock_speed  dual_sim  fc  four_g  int_memory  m_dep  \\\n0            842     0          2.2         0   1       0           7    0.6   \n1           1021     1          0.5         1   0       1          53    0.7   \n2            563     1          0.5         1   2       1          41    0.9   \n3            615     1          2.5         0   0       0          10    0.8   \n4           1821     1          1.2         0  13       1          44    0.6   \n5           1859     0          0.5         1   3       0          22    0.7   \n6           1821     0          1.7         0   4       1          10    0.8   \n7           1954     0          0.5         1   0       0          24    0.8   \n8           1445     1          0.5         0   0       0          53    0.7   \n9            509     1          0.6         1   2       1           9    0.1   \n\n   mobile_wt  n_cores  ...  px_height  px_width   ram  sc_h  sc_w  talk_time  \\\n0        188        2  ...         20       756  2549     9     7         19   \n1        136        3  ...        905      1988  2631    17     3          7   \n2        145        5  ...       1263      1716  2603    11     2          9   \n3        131        6  ...       1216      1786  2769    16     8         11   \n4        141        2  ...       1208      1212  1411     8     2         15   \n5        164        1  ...       1004      1654  1067    17     1         10   \n6        139        8  ...        381      1018  3220    13     8         18   \n7        187        4  ...        512      1149   700    16     3          5   \n8        174        7  ...        386       836  1099    17     1         20   \n9         93        5  ...       1137      1224   513    19    10         12   \n\n   three_g  touch_screen  wifi  price_range  \n0        0             0     1            1  \n1        1             1     0            2  \n2        1             1     0            2  \n3        1             0     0            2  \n4        1             1     0            1  \n5        1             0     0            1  \n6        1             0     1            3  \n7        1             1     1            0  \n8        1             0     0            0  \n9        1             0     0            0  \n\n[10 rows x 21 columns]",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>battery_power</th>\n      <th>blue</th>\n      <th>clock_speed</th>\n      <th>dual_sim</th>\n      <th>fc</th>\n      <th>four_g</th>\n      <th>int_memory</th>\n      <th>m_dep</th>\n      <th>mobile_wt</th>\n      <th>n_cores</th>\n      <th>...</th>\n      <th>px_height</th>\n      <th>px_width</th>\n      <th>ram</th>\n      <th>sc_h</th>\n      <th>sc_w</th>\n      <th>talk_time</th>\n      <th>three_g</th>\n      <th>touch_screen</th>\n      <th>wifi</th>\n      <th>price_range</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>0</th>\n      <td>842</td>\n      <td>0</td>\n      <td>2.2</td>\n      <td>0</td>\n      <td>1</td>\n      <td>0</td>\n      <td>7</td>\n      <td>0.6</td>\n      <td>188</td>\n      <td>2</td>\n      <td>...</td>\n      <td>20</td>\n      <td>756</td>\n      <td>2549</td>\n      <td>9</td>\n      <td>7</td>\n      <td>19</td>\n      <td>0</td>\n      <td>0</td>\n      <td>1</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>1</th>\n      <td>1021</td>\n      <td>1</td>\n      <td>0.5</td>\n      <td>1</td>\n      <td>0</td>\n      <td>1</td>\n      <td>53</td>\n      <td>0.7</td>\n      <td>136</td>\n      <td>3</td>\n      <td>...</td>\n      <td>905</td>\n      <td>1988</td>\n      <td>2631</td>\n      <td>17</td>\n      <td>3</td>\n      <td>7</td>\n      <td>1</td>\n      <td>1</td>\n      <td>0</td>\n      <td>2</td>\n    </tr>\n    <tr>\n      <th>2</th>\n      <td>563</td>\n      <td>1</td>\n      <td>0.5</td>\n      <td>1</td>\n      <td>2</td>\n      <td>1</td>\n      <td>41</td>\n      <td>0.9</td>\n      <td>145</td>\n      <td>5</td>\n      <td>...</td>\n      <td>1263</td>\n      <td>1716</td>\n      <td>2603</td>\n      <td>11</td>\n      <td>2</td>\n      <td>9</td>\n      <td>1</td>\n      <td>1</td>\n      <td>0</td>\n      <td>2</td>\n    </tr>\n    <tr>\n      <th>3</th>\n      <td>615</td>\n      <td>1</td>\n      <td>2.5</td>\n      <td>0</td>\n      <td>0</td>\n      <td>0</td>\n      <td>10</td>\n      <td>0.8</td>\n      <td>131</td>\n      <td>6</td>\n      <td>...</td>\n      <td>1216</td>\n      <td>1786</td>\n      <td>2769</td>\n      <td>16</td>\n      <td>8</td>\n      <td>11</td>\n      <td>1</td>\n      <td>0</td>\n      <td>0</td>\n      <td>2</td>\n    </tr>\n    <tr>\n      <th>4</th>\n      <td>1821</td>\n      <td>1</td>\n      <td>1.2</td>\n      <td>0</td>\n      <td>13</td>\n      <td>1</td>\n      <td>44</td>\n      <td>0.6</td>\n      <td>141</td>\n      <td>2</td>\n      <td>...</td>\n      <td>1208</td>\n      <td>1212</td>\n      <td>1411</td>\n      <td>8</td>\n      <td>2</td>\n      <td>15</td>\n      <td>1</td>\n      <td>1</td>\n      <td>0</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>5</th>\n      <td>1859</td>\n      <td>0</td>\n      <td>0.5</td>\n      <td>1</td>\n      <td>3</td>\n      <td>0</td>\n      <td>22</td>\n      <td>0.7</td>\n      <td>164</td>\n      <td>1</td>\n      <td>...</td>\n      <td>1004</td>\n      <td>1654</td>\n      <td>1067</td>\n      <td>17</td>\n      <td>1</td>\n      <td>10</td>\n      <td>1</td>\n      <td>0</td>\n      <td>0</td>\n      <td>1</td>\n    </tr>\n    <tr>\n      <th>6</th>\n      <td>1821</td>\n      <td>0</td>\n      <td>1.7</td>\n      <td>0</td>\n      <td>4</td>\n      <td>1</td>\n      <td>10</td>\n      <td>0.8</td>\n      <td>139</td>\n      <td>8</td>\n      <td>...</td>\n      <td>381</td>\n      <td>1018</td>\n      <td>3220</td>\n      <td>13</td>\n      <td>8</td>\n      <td>18</td>\n      <td>1</td>\n      <td>0</td>\n      <td>1</td>\n      <td>3</td>\n    </tr>\n    <tr>\n      <th>7</th>\n      <td>1954</td>\n      <td>0</td>\n      <td>0.5</td>\n      <td>1</td>\n      <td>0</td>\n      <td>0</td>\n      <td>24</td>\n      <td>0.8</td>\n      <td>187</td>\n      <td>4</td>\n      <td>...</td>\n      <td>512</td>\n      <td>1149</td>\n      <td>700</td>\n      <td>16</td>\n      <td>3</td>\n      <td>5</td>\n      <td>1</td>\n      <td>1</td>\n      <td>1</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>8</th>\n      <td>1445</td>\n      <td>1</td>\n      <td>0.5</td>\n      <td>0</td>\n      <td>0</td>\n      <td>0</td>\n      <td>53</td>\n      <td>0.7</td>\n      <td>174</td>\n      <td>7</td>\n      <td>...</td>\n      <td>386</td>\n      <td>836</td>\n      <td>1099</td>\n      <td>17</td>\n      <td>1</td>\n      <td>20</td>\n      <td>1</td>\n      <td>0</td>\n      <td>0</td>\n      <td>0</td>\n    </tr>\n    <tr>\n      <th>9</th>\n      <td>509</td>\n      <td>1</td>\n      <td>0.6</td>\n      <td>1</td>\n      <td>2</td>\n      <td>1</td>\n      <td>9</td>\n      <td>0.1</td>\n      <td>93</td>\n      <td>5</td>\n      <td>...</td>\n      <td>1137</td>\n      <td>1224</td>\n      <td>513</td>\n      <td>19</td>\n      <td>10</td>\n      <td>12</td>\n      <td>1</td>\n      <td>0</td>\n      <td>0</td>\n      <td>0</td>\n    </tr>\n  </tbody>\n</table>\n<p>10 rows × 21 columns</p>\n</div>"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data = pd.read_csv('./data/data.csv')\n",
    "data.head(10)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:12:43.540319600Z",
     "start_time": "2025-10-11T04:12:43.518980Z"
    }
   },
   "id": "f0d7165938d381b1"
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "outputs": [
    {
     "data": {
      "text/plain": "                count        mean          std    min      25%     50%  \\\nbattery_power  2000.0  1238.51850   439.418206  501.0   851.75  1226.0   \nblue           2000.0     0.49500     0.500100    0.0     0.00     0.0   \nclock_speed    2000.0     1.52225     0.816004    0.5     0.70     1.5   \ndual_sim       2000.0     0.50950     0.500035    0.0     0.00     1.0   \nfc             2000.0     4.30950     4.341444    0.0     1.00     3.0   \nfour_g         2000.0     0.52150     0.499662    0.0     0.00     1.0   \nint_memory     2000.0    32.04650    18.145715    2.0    16.00    32.0   \nm_dep          2000.0     0.50175     0.288416    0.1     0.20     0.5   \nmobile_wt      2000.0   140.24900    35.399655   80.0   109.00   141.0   \nn_cores        2000.0     4.52050     2.287837    1.0     3.00     4.0   \npc             2000.0     9.91650     6.064315    0.0     5.00    10.0   \npx_height      2000.0   645.10800   443.780811    0.0   282.75   564.0   \npx_width       2000.0  1251.51550   432.199447  500.0   874.75  1247.0   \nram            2000.0  2124.21300  1084.732044  256.0  1207.50  2146.5   \nsc_h           2000.0    12.30650     4.213245    5.0     9.00    12.0   \nsc_w           2000.0     5.76700     4.356398    0.0     2.00     5.0   \ntalk_time      2000.0    11.01100     5.463955    2.0     6.00    11.0   \nthree_g        2000.0     0.76150     0.426273    0.0     1.00     1.0   \ntouch_screen   2000.0     0.50300     0.500116    0.0     0.00     1.0   \nwifi           2000.0     0.50700     0.500076    0.0     0.00     1.0   \nprice_range    2000.0     1.50000     1.118314    0.0     0.75     1.5   \n\n                   75%     max  \nbattery_power  1615.25  1998.0  \nblue              1.00     1.0  \nclock_speed       2.20     3.0  \ndual_sim          1.00     1.0  \nfc                7.00    19.0  \nfour_g            1.00     1.0  \nint_memory       48.00    64.0  \nm_dep             0.80     1.0  \nmobile_wt       170.00   200.0  \nn_cores           7.00     8.0  \npc               15.00    20.0  \npx_height       947.25  1960.0  \npx_width       1633.00  1998.0  \nram            3064.50  3998.0  \nsc_h             16.00    19.0  \nsc_w              9.00    18.0  \ntalk_time        16.00    20.0  \nthree_g           1.00     1.0  \ntouch_screen      1.00     1.0  \nwifi              1.00     1.0  \nprice_range       2.25     3.0  ",
      "text/html": "<div>\n<style scoped>\n    .dataframe tbody tr th:only-of-type {\n        vertical-align: middle;\n    }\n\n    .dataframe tbody tr th {\n        vertical-align: top;\n    }\n\n    .dataframe thead th {\n        text-align: right;\n    }\n</style>\n<table border=\"1\" class=\"dataframe\">\n  <thead>\n    <tr style=\"text-align: right;\">\n      <th></th>\n      <th>count</th>\n      <th>mean</th>\n      <th>std</th>\n      <th>min</th>\n      <th>25%</th>\n      <th>50%</th>\n      <th>75%</th>\n      <th>max</th>\n    </tr>\n  </thead>\n  <tbody>\n    <tr>\n      <th>battery_power</th>\n      <td>2000.0</td>\n      <td>1238.51850</td>\n      <td>439.418206</td>\n      <td>501.0</td>\n      <td>851.75</td>\n      <td>1226.0</td>\n      <td>1615.25</td>\n      <td>1998.0</td>\n    </tr>\n    <tr>\n      <th>blue</th>\n      <td>2000.0</td>\n      <td>0.49500</td>\n      <td>0.500100</td>\n      <td>0.0</td>\n      <td>0.00</td>\n      <td>0.0</td>\n      <td>1.00</td>\n      <td>1.0</td>\n    </tr>\n    <tr>\n      <th>clock_speed</th>\n      <td>2000.0</td>\n      <td>1.52225</td>\n      <td>0.816004</td>\n      <td>0.5</td>\n      <td>0.70</td>\n      <td>1.5</td>\n      <td>2.20</td>\n      <td>3.0</td>\n    </tr>\n    <tr>\n      <th>dual_sim</th>\n      <td>2000.0</td>\n      <td>0.50950</td>\n      <td>0.500035</td>\n      <td>0.0</td>\n      <td>0.00</td>\n      <td>1.0</td>\n      <td>1.00</td>\n      <td>1.0</td>\n    </tr>\n    <tr>\n      <th>fc</th>\n      <td>2000.0</td>\n      <td>4.30950</td>\n      <td>4.341444</td>\n      <td>0.0</td>\n      <td>1.00</td>\n      <td>3.0</td>\n      <td>7.00</td>\n      <td>19.0</td>\n    </tr>\n    <tr>\n      <th>four_g</th>\n      <td>2000.0</td>\n      <td>0.52150</td>\n      <td>0.499662</td>\n      <td>0.0</td>\n      <td>0.00</td>\n      <td>1.0</td>\n      <td>1.00</td>\n      <td>1.0</td>\n    </tr>\n    <tr>\n      <th>int_memory</th>\n      <td>2000.0</td>\n      <td>32.04650</td>\n      <td>18.145715</td>\n      <td>2.0</td>\n      <td>16.00</td>\n      <td>32.0</td>\n      <td>48.00</td>\n      <td>64.0</td>\n    </tr>\n    <tr>\n      <th>m_dep</th>\n      <td>2000.0</td>\n      <td>0.50175</td>\n      <td>0.288416</td>\n      <td>0.1</td>\n      <td>0.20</td>\n      <td>0.5</td>\n      <td>0.80</td>\n      <td>1.0</td>\n    </tr>\n    <tr>\n      <th>mobile_wt</th>\n      <td>2000.0</td>\n      <td>140.24900</td>\n      <td>35.399655</td>\n      <td>80.0</td>\n      <td>109.00</td>\n      <td>141.0</td>\n      <td>170.00</td>\n      <td>200.0</td>\n    </tr>\n    <tr>\n      <th>n_cores</th>\n      <td>2000.0</td>\n      <td>4.52050</td>\n      <td>2.287837</td>\n      <td>1.0</td>\n      <td>3.00</td>\n      <td>4.0</td>\n      <td>7.00</td>\n      <td>8.0</td>\n    </tr>\n    <tr>\n      <th>pc</th>\n      <td>2000.0</td>\n      <td>9.91650</td>\n      <td>6.064315</td>\n      <td>0.0</td>\n      <td>5.00</td>\n      <td>10.0</td>\n      <td>15.00</td>\n      <td>20.0</td>\n    </tr>\n    <tr>\n      <th>px_height</th>\n      <td>2000.0</td>\n      <td>645.10800</td>\n      <td>443.780811</td>\n      <td>0.0</td>\n      <td>282.75</td>\n      <td>564.0</td>\n      <td>947.25</td>\n      <td>1960.0</td>\n    </tr>\n    <tr>\n      <th>px_width</th>\n      <td>2000.0</td>\n      <td>1251.51550</td>\n      <td>432.199447</td>\n      <td>500.0</td>\n      <td>874.75</td>\n      <td>1247.0</td>\n      <td>1633.00</td>\n      <td>1998.0</td>\n    </tr>\n    <tr>\n      <th>ram</th>\n      <td>2000.0</td>\n      <td>2124.21300</td>\n      <td>1084.732044</td>\n      <td>256.0</td>\n      <td>1207.50</td>\n      <td>2146.5</td>\n      <td>3064.50</td>\n      <td>3998.0</td>\n    </tr>\n    <tr>\n      <th>sc_h</th>\n      <td>2000.0</td>\n      <td>12.30650</td>\n      <td>4.213245</td>\n      <td>5.0</td>\n      <td>9.00</td>\n      <td>12.0</td>\n      <td>16.00</td>\n      <td>19.0</td>\n    </tr>\n    <tr>\n      <th>sc_w</th>\n      <td>2000.0</td>\n      <td>5.76700</td>\n      <td>4.356398</td>\n      <td>0.0</td>\n      <td>2.00</td>\n      <td>5.0</td>\n      <td>9.00</td>\n      <td>18.0</td>\n    </tr>\n    <tr>\n      <th>talk_time</th>\n      <td>2000.0</td>\n      <td>11.01100</td>\n      <td>5.463955</td>\n      <td>2.0</td>\n      <td>6.00</td>\n      <td>11.0</td>\n      <td>16.00</td>\n      <td>20.0</td>\n    </tr>\n    <tr>\n      <th>three_g</th>\n      <td>2000.0</td>\n      <td>0.76150</td>\n      <td>0.426273</td>\n      <td>0.0</td>\n      <td>1.00</td>\n      <td>1.0</td>\n      <td>1.00</td>\n      <td>1.0</td>\n    </tr>\n    <tr>\n      <th>touch_screen</th>\n      <td>2000.0</td>\n      <td>0.50300</td>\n      <td>0.500116</td>\n      <td>0.0</td>\n      <td>0.00</td>\n      <td>1.0</td>\n      <td>1.00</td>\n      <td>1.0</td>\n    </tr>\n    <tr>\n      <th>wifi</th>\n      <td>2000.0</td>\n      <td>0.50700</td>\n      <td>0.500076</td>\n      <td>0.0</td>\n      <td>0.00</td>\n      <td>1.0</td>\n      <td>1.00</td>\n      <td>1.0</td>\n    </tr>\n    <tr>\n      <th>price_range</th>\n      <td>2000.0</td>\n      <td>1.50000</td>\n      <td>1.118314</td>\n      <td>0.0</td>\n      <td>0.75</td>\n      <td>1.5</td>\n      <td>2.25</td>\n      <td>3.0</td>\n    </tr>\n  </tbody>\n</table>\n</div>"
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.describe().T"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:12:43.593771600Z",
     "start_time": "2025-10-11T04:12:43.538017100Z"
    }
   },
   "id": "bc05c9c2b5015fa2"
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "RangeIndex: 2000 entries, 0 to 1999\n",
      "Data columns (total 21 columns):\n",
      " #   Column         Non-Null Count  Dtype  \n",
      "---  ------         --------------  -----  \n",
      " 0   battery_power  2000 non-null   int64  \n",
      " 1   blue           2000 non-null   int64  \n",
      " 2   clock_speed    2000 non-null   float64\n",
      " 3   dual_sim       2000 non-null   int64  \n",
      " 4   fc             2000 non-null   int64  \n",
      " 5   four_g         2000 non-null   int64  \n",
      " 6   int_memory     2000 non-null   int64  \n",
      " 7   m_dep          2000 non-null   float64\n",
      " 8   mobile_wt      2000 non-null   int64  \n",
      " 9   n_cores        2000 non-null   int64  \n",
      " 10  pc             2000 non-null   int64  \n",
      " 11  px_height      2000 non-null   int64  \n",
      " 12  px_width       2000 non-null   int64  \n",
      " 13  ram            2000 non-null   int64  \n",
      " 14  sc_h           2000 non-null   int64  \n",
      " 15  sc_w           2000 non-null   int64  \n",
      " 16  talk_time      2000 non-null   int64  \n",
      " 17  three_g        2000 non-null   int64  \n",
      " 18  touch_screen   2000 non-null   int64  \n",
      " 19  wifi           2000 non-null   int64  \n",
      " 20  price_range    2000 non-null   int64  \n",
      "dtypes: float64(2), int64(19)\n",
      "memory usage: 328.3 KB\n"
     ]
    }
   ],
   "source": [
    "data.info()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:12:43.593771600Z",
     "start_time": "2025-10-11T04:12:43.562907Z"
    }
   },
   "id": "72f3b4b17e68d49d"
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "outputs": [],
   "source": [
    "x = data.iloc[:, :-1]\n",
    "y = data.iloc[:, -1]\n",
    "x = x.astype(np.float32)\n",
    "x_train, x_valid, y_train, y_valid = train_test_split(x, y, train_size=0.8, random_state=42)\n",
    "\n",
    "# 优化①: 数据标准化\n",
    "transfer = StandardScaler()\n",
    "x_train = transfer.fit_transform(x_train)\n",
    "x_valid = transfer.transform(x_valid)\n",
    "\n",
    "train_dataset = TensorDataset(torch.tensor(x_train), torch.tensor(y_train.values))\n",
    "valid_dataset = TensorDataset(torch.tensor(x_valid), torch.tensor(y_valid.values))\n",
    "input_dim = x.shape[1]\n",
    "output_dim = len(np.unique(y))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:12:43.593771600Z",
     "start_time": "2025-10-11T04:12:43.571758700Z"
    }
   },
   "id": "660bba3a96c5d469"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 3. 构建多分类模型"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "e7f43c519f8e52ab"
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "outputs": [],
   "source": [
    "class Model(nn.Module):\n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "\n",
    "        # 优化②:增加网络深度\n",
    "        self.linear1 = nn.Linear(input_dim, 64)\n",
    "        self.linear2 = nn.Linear(64, 128)\n",
    "        self.linear3 = nn.Linear(128, 256)\n",
    "        self.linear4 = nn.Linear(256, output_dim)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = torch.relu(self.linear1(x))\n",
    "        x = torch.relu(self.linear2(x))\n",
    "        x = torch.relu(self.linear3(x))\n",
    "        output = self.linear4(x)  # 后续CrossEntropyLoss损失函数中包含softmax过程, 当前步骤不进行softmax操作\n",
    "        return output"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:12:43.593771600Z",
     "start_time": "2025-10-11T04:12:43.583254800Z"
    }
   },
   "id": "e0c55d6b11db5f32"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 4. 模型训练"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "1cd02a7a3e2bb769"
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 1/100 loss: 1.355034 time: 0.26s\n",
      "epoch: 2/100 loss: 1.156616 time: 0.25s\n",
      "epoch: 3/100 loss: 0.799909 time: 0.28s\n",
      "epoch: 4/100 loss: 0.550621 time: 0.22s\n",
      "epoch: 5/100 loss: 0.414769 time: 0.23s\n",
      "epoch: 6/100 loss: 0.326920 time: 0.26s\n",
      "epoch: 7/100 loss: 0.273320 time: 0.24s\n",
      "epoch: 8/100 loss: 0.237319 time: 0.27s\n",
      "epoch: 9/100 loss: 0.210320 time: 0.26s\n",
      "epoch: 10/100 loss: 0.189582 time: 0.26s\n",
      "epoch: 11/100 loss: 0.171294 time: 0.27s\n",
      "epoch: 12/100 loss: 0.157772 time: 0.27s\n",
      "epoch: 13/100 loss: 0.145500 time: 0.27s\n",
      "epoch: 14/100 loss: 0.136037 time: 0.26s\n",
      "epoch: 15/100 loss: 0.124214 time: 0.25s\n",
      "epoch: 16/100 loss: 0.115976 time: 0.22s\n",
      "epoch: 17/100 loss: 0.110114 time: 0.23s\n",
      "epoch: 18/100 loss: 0.100231 time: 0.23s\n",
      "epoch: 19/100 loss: 0.093626 time: 0.23s\n",
      "epoch: 20/100 loss: 0.087904 time: 0.23s\n",
      "epoch: 21/100 loss: 0.085245 time: 0.23s\n",
      "epoch: 22/100 loss: 0.076641 time: 0.23s\n",
      "epoch: 23/100 loss: 0.074465 time: 0.23s\n",
      "epoch: 24/100 loss: 0.068936 time: 0.23s\n",
      "epoch: 25/100 loss: 0.063464 time: 0.23s\n",
      "epoch: 26/100 loss: 0.059576 time: 0.23s\n",
      "epoch: 27/100 loss: 0.054813 time: 0.23s\n",
      "epoch: 28/100 loss: 0.050359 time: 0.23s\n",
      "epoch: 29/100 loss: 0.049584 time: 0.23s\n",
      "epoch: 30/100 loss: 0.044611 time: 0.23s\n",
      "epoch: 31/100 loss: 0.042414 time: 0.23s\n",
      "epoch: 32/100 loss: 0.037418 time: 0.23s\n",
      "epoch: 33/100 loss: 0.035490 time: 0.23s\n",
      "epoch: 34/100 loss: 0.031073 time: 0.23s\n",
      "epoch: 35/100 loss: 0.029732 time: 0.23s\n",
      "epoch: 36/100 loss: 0.027207 time: 0.23s\n",
      "epoch: 37/100 loss: 0.025442 time: 0.23s\n",
      "epoch: 38/100 loss: 0.024490 time: 0.23s\n",
      "epoch: 39/100 loss: 0.020648 time: 0.23s\n",
      "epoch: 40/100 loss: 0.019813 time: 0.23s\n",
      "epoch: 41/100 loss: 0.017218 time: 0.23s\n",
      "epoch: 42/100 loss: 0.016892 time: 0.22s\n",
      "epoch: 43/100 loss: 0.014744 time: 0.23s\n",
      "epoch: 44/100 loss: 0.012919 time: 0.23s\n",
      "epoch: 45/100 loss: 0.011977 time: 0.22s\n",
      "epoch: 46/100 loss: 0.010784 time: 0.22s\n",
      "epoch: 47/100 loss: 0.009803 time: 0.23s\n",
      "epoch: 48/100 loss: 0.008870 time: 0.23s\n",
      "epoch: 49/100 loss: 0.008290 time: 0.23s\n",
      "epoch: 50/100 loss: 0.007690 time: 0.22s\n",
      "epoch: 51/100 loss: 0.006957 time: 0.23s\n",
      "epoch: 52/100 loss: 0.005881 time: 0.23s\n",
      "epoch: 53/100 loss: 0.005511 time: 0.22s\n",
      "epoch: 54/100 loss: 0.005039 time: 0.22s\n",
      "epoch: 55/100 loss: 0.004566 time: 0.24s\n",
      "epoch: 56/100 loss: 0.003956 time: 0.23s\n",
      "epoch: 57/100 loss: 0.003649 time: 0.22s\n",
      "epoch: 58/100 loss: 0.003209 time: 0.23s\n",
      "epoch: 59/100 loss: 0.002839 time: 0.22s\n",
      "epoch: 60/100 loss: 0.002582 time: 0.23s\n",
      "epoch: 61/100 loss: 0.002353 time: 0.22s\n",
      "epoch: 62/100 loss: 0.002103 time: 0.24s\n",
      "epoch: 63/100 loss: 0.001882 time: 0.26s\n",
      "epoch: 64/100 loss: 0.001676 time: 0.22s\n",
      "epoch: 65/100 loss: 0.001575 time: 0.23s\n",
      "epoch: 66/100 loss: 0.001373 time: 0.23s\n",
      "epoch: 67/100 loss: 0.001264 time: 0.23s\n",
      "epoch: 68/100 loss: 0.001110 time: 0.27s\n",
      "epoch: 69/100 loss: 0.000970 time: 0.23s\n",
      "epoch: 70/100 loss: 0.000892 time: 0.23s\n",
      "epoch: 71/100 loss: 0.000806 time: 0.23s\n",
      "epoch: 72/100 loss: 0.000723 time: 0.23s\n",
      "epoch: 73/100 loss: 0.000618 time: 0.23s\n",
      "epoch: 74/100 loss: 0.000574 time: 0.23s\n",
      "epoch: 75/100 loss: 0.000500 time: 0.23s\n",
      "epoch: 76/100 loss: 0.000457 time: 0.23s\n",
      "epoch: 77/100 loss: 0.000425 time: 0.23s\n",
      "epoch: 78/100 loss: 0.000387 time: 0.23s\n",
      "epoch: 79/100 loss: 0.000325 time: 0.23s\n",
      "epoch: 80/100 loss: 0.000293 time: 0.23s\n",
      "epoch: 81/100 loss: 0.000264 time: 0.23s\n",
      "epoch: 82/100 loss: 0.000234 time: 0.23s\n",
      "epoch: 83/100 loss: 0.000215 time: 0.23s\n",
      "epoch: 84/100 loss: 0.000192 time: 0.23s\n",
      "epoch: 85/100 loss: 0.000171 time: 0.23s\n",
      "epoch: 86/100 loss: 0.000149 time: 0.23s\n",
      "epoch: 87/100 loss: 0.000131 time: 0.23s\n",
      "epoch: 88/100 loss: 0.000120 time: 0.25s\n",
      "epoch: 89/100 loss: 0.000106 time: 0.23s\n",
      "epoch: 90/100 loss: 0.000101 time: 0.23s\n",
      "epoch: 91/100 loss: 0.000087 time: 0.25s\n",
      "epoch: 92/100 loss: 0.000083 time: 0.26s\n",
      "epoch: 93/100 loss: 0.000071 time: 0.27s\n",
      "epoch: 94/100 loss: 0.000063 time: 0.25s\n",
      "epoch: 95/100 loss: 0.000055 time: 0.23s\n",
      "epoch: 96/100 loss: 0.000051 time: 0.23s\n",
      "epoch: 97/100 loss: 0.000045 time: 0.22s\n",
      "epoch: 98/100 loss: 0.000044 time: 0.23s\n",
      "epoch: 99/100 loss: 0.000038 time: 0.23s\n",
      "epoch: 100/100 loss: 0.000033 time: 0.23s\n"
     ]
    }
   ],
   "source": [
    "torch.manual_seed(42)\n",
    "dataloader = DataLoader(train_dataset, shuffle=True, batch_size=8)\n",
    "model = Model()\n",
    "criterion = nn.CrossEntropyLoss()\n",
    "# 优化③:使用Adam优化方法\n",
    "# 优化④:学习率变为1e-4\n",
    "optimizer = optim.Adam(model.parameters(), lr=1e-4)\n",
    "# 优化⑤:增加训练次数\n",
    "epoch = 100\n",
    "loss_history = []\n",
    "for epoch_idx in range(epoch):\n",
    "    start_time = time.time()\n",
    "    total_loss = 0.0\n",
    "    total_num = 0\n",
    "    for x_batch, y_batch in dataloader:\n",
    "        model.train()  # 训练模式\n",
    "        output = model(x_batch)\n",
    "        loss = criterion(output, y_batch)\n",
    "        optimizer.zero_grad()\n",
    "        loss.backward()\n",
    "        optimizer.step()\n",
    "        total_num += 1\n",
    "        total_loss += loss\n",
    "    avg_loss = total_loss / total_num\n",
    "    loss_history.append(avg_loss.item())\n",
    "    end_time = time.time()\n",
    "    # 打印损失变换结果\n",
    "    print(f'epoch: {epoch_idx + 1}/{epoch} loss: {(avg_loss):.6f} time: {(end_time - start_time):.2f}s')\n",
    "torch.save(model.state_dict(), './model/model.pth')"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:13:08.082661200Z",
     "start_time": "2025-10-11T04:12:43.586727500Z"
    }
   },
   "id": "22ab48b7abc65c98"
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "outputs": [
    {
     "data": {
      "text/plain": "<Figure size 1000x600 with 1 Axes>",
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA04AAAIjCAYAAAA0vUuxAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAATuBJREFUeJzt3Ql4VNX5x/F3shAMEkAgLCEat4pIBUTBqBSoLKLFBalrhdIqVaFlqVVwAdEqrggqQkURN0DlD7ihgAgCiiIo1gVQCwgEwiJCIGFN7v95zzghk0wyyWRm7r0z38/zTGfuMrknySnOL+ec93osy7IEAAAAAFCuhPIPAQAAAAAUwQkAAAAAgiA4AQAAAEAQBCcAAAAACILgBAAAAABBEJwAAAAAIAiCEwAAAAAEQXACAAAAgCAITgAAAAAQBMEJAOLAn//8Z8nKygrpvffee694PJ6wtwmx3+eOPfZYu5sBAGFDcAIAG2kgqcxj0aJFEo/48F3xz6a8/lKzZk27mwcAMSfJ7gYAQDx7+eWX/bZfeuklmT9/fpn9p59+erWuM2nSJCkqKgrpvXfffbcMGzasWtdHZKSkpMhzzz1XZn9iYqIt7QGAWEZwAgAb/elPf/Lb/vTTT01wKr2/tIKCAklNTa30dZKTk0NuY1JSknnAefT3EqyvAADCg6l6AOBwnTp1kpYtW8rKlSvld7/7nQlMd955pzn25ptvyiWXXCJNmzY1ow8nn3yy3H///VJYWFjhGqcNGzaYKV2PPfaYPPvss+Z9+v5zzjlHPv/886BrnHR74MCBMnv2bNM2fe8ZZ5wh77//fpn26zTDs88+20wf0+v85z//Cfu6qTfeeEPatm0rxxxzjDRo0MCEiZycHL9zcnNzpV+/ftKsWTPT3iZNmshll11mfhY+K1askO7du5uvoV/rxBNPlL/85S8VXvsPf/iDnHTSSQGPZWdnm+/dR0PxBRdcIHXr1jVTEE877bTi32WkTJkyxfysFy9eLH/729+kfv36kpaWJn369JFffvmlzPnPPPOM+V3qz0j71YABA2T37t1lzvvss8/k4osvlnr16kmtWrXkzDPPlHHjxpU5T38Pl19+ufl+GzZsKLfddluZ/gkAbsCfEAHABX7++Wfp0aOHXHPNNSYUNGrUqPhDsX4gHTp0qHn+8MMPZcSIEZKXlyePPvpo0K87depU2bt3r/lArR+uH3nkEenVq5esW7cu6CjV0qVLZebMmXLrrbdK7dq15cknn5Qrr7xSNm7caD6cqy+//FIuuugiE1JGjRplPjDfd9995gN0uOjPQAORhr7Ro0fLtm3bzAf4jz/+2FxfQ4rStn377bfy97//3YTI7du3myCj7fVtd+vWzbRNpybq+zRU6fdYkauvvtqEEA2c2gafn376yYwg+n4Pem0NWRow9GegweTHH3807ayOnTt3ltlXo0YNE45K0qCr35OG1rVr18qECRNMGzXY+kKsHtPfU5cuXeSWW24pPk+/N22nr0/oz02/F/29Dho0SBo3biyrV6+Wd955x2z76O9bg2j79u1NSP/ggw/k8ccfNwFavz4AuIoFAHCMAQMGWKX/ae7YsaPZN3HixDLnFxQUlNn3t7/9zUpNTbUOHDhQvK9v377WCSecULy9fv168zXr169v7dq1q3j/m2++afa//fbbxftGjhxZpk26XaNGDevHH38s3vfVV1+Z/U899VTxvp49e5q25OTkFO/74YcfrKSkpDJfMxBtd61atco9fujQISs9Pd1q2bKltX///uL977zzjvn6I0aMMNu//PKL2X700UfL/VqzZs0y53z++edWVezZs8dKSUmx/vnPf/rtf+SRRyyPx2P99NNPZvuJJ54wX3/Hjh1WOOjPRr9eoEf37t2Lz3vhhRfMvrZt25qfV8n26X79navt27eb32m3bt2swsLC4vOefvppc97kyZPN9pEjR6wTTzzR9Cf9uZZUVFRUpn333Xef3zlt2rQxbQEAt2GqHgC4gI5O6KhKaTqdzEdHjnT0oUOHDmYN1Jo1a4J+XR0t0alWPvpepSNOweiohI4c+OhIio5y+N6row06wqDTtHTKl88pp5xiRs/CQafW6UiRjnqVrCSn0xebN28u7777bvHPSUdhdHQl0PQ05RuZ0lGTw4cPV7oN+j3r9/P6669rEize/9prr8m5554rxx9/vN/X1+mVoRbqKE2/Zx39Kf146KGHypzbv39/v1FEHfHRNVJz5swx2/q7OnTokAwePFgSEo5+PLjpppvM9+j7Weoo3vr16815vu/JJ9D0y5tvvtlvW/tYZfoXADgNwQkAXCAjI8N88C9Np39dccUVUqdOHfPhVqeZ+YoF7NmzJ+jX9X2o9/GFqPLCRUXv9b3f914NNPv3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a/oNAtGpwKVveaDrVk444QTzWv8N0g8oJfuOTtHS9QX0nfhVUFBg1pmUpH8c1s81in6DYCrTR/RZ/+Cnfxz00c9G2s90LZQj2F2dIpZNnz7dVAuZMmWKqRTSv39/q27dulZubq7dTYND3HLLLVadOnWsRYsWWVu3bi1+FBQUFJ9z8803W8cff7z14YcfWitWrLCys7PNAyipZFU9Rb9BIMuXL7eSkpKsBx54wPrhhx+sV1991UpNTbVeeeWV4nMeeugh89+qN9980/rvf/9rXXbZZdaJJ55o7d+/39a2wz59+/a1MjIyrHfeecdav369NXPmTKtBgwbW7bffXnwO/QZ79+61vvzyS/PQiDFmzBjz+qeffqp0H7nooousNm3aWJ999pm1dOlSUzn22muvtZyC4BRhTz31lPnwUqNGDVOe/NNPP7W7SXAQ/Ycl0OOFF14oPkf/Qbn11lutevXqmQ84V1xxhQlXQEXBiX6D8rz99ttWy5YtzR/2mjdvbj377LN+x7Vs8D333GM1atTInHPhhRdaa9euta29sF9eXp7590U/z9SsWdM66aSTrLvuuss6ePBg8Tn0GyxcuDDgZxoN3pXtIz///LMJSscee6yVlpZm9evXzwQyp/Do/9g96gUAAAAATsYaJwAAAAAIguAEAAAAAEEQnAAAAAAgCIITAAAAAARBcAIAAACAIAhOAAAAABAEwQkAAAAAgiA4AQAAAEAQBCcAAKrA4/HI7Nmz7W4GACDKCE4AANf485//bIJL6cdFF11kd9MAADEuye4GAABQFRqSXnjhBb99KSkptrUHABAfGHECALiKhqTGjRv7PerVq2eO6ejThAkTpEePHnLMMcfISSedJDNmzPB7/9dffy2///3vzfH69etL//79Zd++fX7nTJ48Wc444wxzrSZNmsjAgQP9ju/cuVOuuOIKSU1NlVNPPVXeeuutKHznAAA7EZwAADHlnnvukSuvvFK++uoruf766+Waa66R1atXm2P5+fnSvXt3E7Q+//xzeeONN+SDDz7wC0YavAYMGGAClYYsDUWnnHKK3zVGjRolV111lfz3v/+Viy++2Fxn165dUf9eAQDR47Esy4ri9QAAqNYap1deeUVq1qzpt//OO+80Dx1xuvnmm0348Tn33HPlrLPOkmeeeUYmTZokd9xxh2zatElq1apljs+ZM0d69uwpW7ZskUaNGklGRob069dP/v3vfwdsg17j7rvvlvvvv784jB177LHy3nvvsdYKAGIYa5wAAK7SuXNnv2CkjjvuuOLX2dnZfsd0e9WqVea1jjy1atWqODSp888/X4qKimTt2rUmFGmAuvDCCytsw5lnnln8Wr9WWlqabN++vdrfGwDAuQhOAABX0aBSeupcuOi6p8pITk7229bApeELABC7WOMEAIgpn376aZnt008/3bzWZ137pNPrfD7++GNJSEiQ0047TWrXri1ZWVmyYMGCqLcbAOBsjDgBAFzl4MGDkpub67cvKSlJGjRoYF5rwYezzz5bLrjgAnn11Vdl+fLl8vzzz5tjWsRh5MiR0rdvX7n33ntlx44d8ve//11uuOEGs75J6X5dJ5Wenm6q8+3du9eEKz0PABC/CE4AAFd5//33TYnwknS0aM2aNcUV76ZPny633nqrOW/atGnSokULc0zLh8+dO1cGDRok55xzjtnWCnxjxowp/loaqg4cOCBPPPGE3HbbbSaQ9e7dO8rfJQDAaaiqBwCIGbrWaNasWXL55Zfb3RQAQIxhjRMAAAAABEFwAgAAAIAgWOMEAIgZzD4HAEQKI04AAAAAEATBCQAAAACCIDgBAAAAQBAEJwAAAAAIguAEAAAAAEEQnAAAAAAgCIITAAAAAARBcAIAAAAAqdj/A056pQq6Cwb/AAAAAElFTkSuQmCC"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "plt.plot(range(1, epoch + 1), loss_history, marker='o', linestyle='-', color='b')\n",
    "plt.title('Training Loss vs. Epoch')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Loss')\n",
    "plt.grid(True)\n",
    "plt.show()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:13:08.193761100Z",
     "start_time": "2025-10-11T04:13:08.077894100Z"
    }
   },
   "id": "32233e65df68132b"
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "outputs": [
    {
     "data": {
      "text/plain": "==========================================================================================\nLayer (type:depth-idx)                   Output Shape              Param #\n==========================================================================================\nModel                                    [4]                       --\n├─Linear: 1-1                            [64]                      1,344\n├─Linear: 1-2                            [128]                     8,320\n├─Linear: 1-3                            [256]                     33,024\n├─Linear: 1-4                            [4]                       1,028\n==========================================================================================\nTotal params: 43,716\nTrainable params: 43,716\nNon-trainable params: 0\nTotal mult-adds (Units.MEGABYTES): 9.61\n==========================================================================================\nInput size (MB): 0.00\nForward/backward pass size (MB): 0.00\nParams size (MB): 0.17\nEstimated Total Size (MB): 0.18\n=========================================================================================="
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "summary(model, input_size=(input_dim,))"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:13:08.201135800Z",
     "start_time": "2025-10-11T04:13:08.190471100Z"
    }
   },
   "id": "a78603978755f1c5"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 5. 模型评估"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "72d54f115562d2d5"
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy: 0.9400\n"
     ]
    }
   ],
   "source": [
    "eval_model = Model()\n",
    "eval_model.load_state_dict(torch.load('./model/model.pth'))\n",
    "dataloader_valid = DataLoader(valid_dataset, batch_size=8, shuffle=False)\n",
    "correct = 0\n",
    "for x_valid_batch, y_valid_batch in dataloader_valid:\n",
    "    eval_model.eval()\n",
    "    output_valid = eval_model(x_valid_batch)\n",
    "    y_pred = torch.argmax(output_valid, dim=1)\n",
    "    correct += (y_pred == y_valid_batch).sum()\n",
    "print(f'Accuracy: {(correct / len(valid_dataset)):.4f}')"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-10-11T04:13:08.235215800Z",
     "start_time": "2025-10-11T04:13:08.198808200Z"
    }
   },
   "id": "d56aace6f28b10c2"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
